//
//  BWSecurities.m
//  YueXiang
//
//  Created by Houge on 2021/5/28.
//

#import "BWSecurities.h"
#import "BWMethod.h"

@implementation BWSecurities

/// MD5加密
+ (NSString *)md5EncryptWithString:(NSString *)string {
    const char *cStr = [string UTF8String];
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5(cStr, (CC_LONG)strlen(cStr), digest);
    NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [result appendFormat:@"%02X", digest[i]];
    }
    return result;
}

/// 对一个字符串进行base64编码
+ (NSString *)base64EncodeString:(NSString *)string {
       //1.先转换为二进制数据
       NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
       //2.对二进制数据进行base64编码,完成之后返回字符串
       return [data base64EncodedStringWithOptions:0];
}

/// 对base64编码之后的字符串解码
+ (NSString *)base64DecodeString:(NSString *)string {
    //注意:该字符串是base64编码后的字符串
    //1.转换为二进制数据(完成了解码的过程)
    NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
    //2.把二进制数据在转换为字符串
    return [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
}

/// AES加密
+ (NSString *)aesEncrypt:(NSString *)sourceStr {
    if (!sourceStr) {
        return nil;
    }
    
    // 截取SecurityKey
    NSString *subAesStr = [SecretKey substringWithRange:NSMakeRange(8, SecretKey.length - 16)];
    NSLog(@"subAesStr === %@", subAesStr);
    //先对加密的字符串进行base64解码
    NSString *keyDecodeStr = [self base64DecodeString:subAesStr];
    NSLog(@"keyDecodeStr === %@", keyDecodeStr);
    // 设置密钥
    char keyPtr[kCCKeySizeAES256 + 1];
    bzero(keyPtr, sizeof(keyPtr));
    [keyDecodeStr getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    NSLog(@"设置密钥 === %s", keyPtr);
    
    // 生成iv
    NSString *ivStr = [self getRandomStringWithNum:16];
    char ivPtr[kCCKeySizeAES128 + 1];
    bzero(ivPtr, sizeof(ivPtr));
    [ivStr getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
    NSLog(@"生成iv === ivStr: %@ --- ivPtr: %s", ivStr, ivPtr);
    
    // 需要加密的数据
    NSData *sourceData = [sourceStr dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"需要加密的数据 === %@", sourceData);
    NSUInteger dataLength = [sourceData length];
    
    // 设置输出缓冲区
    size_t buffersize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(buffersize);
    size_t numBytesEncrypted = 0;
    
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionPKCS7Padding,
                                          keyPtr,
                                          kCCKeySizeAES256,
                                          ivPtr,
                                          sourceData.bytes,
                                          dataLength,
                                          buffer,
                                          buffersize,
                                          &numBytesEncrypted);
    
    if (cryptStatus == kCCSuccess) {
        NSData *encryptData = [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        //对加密后的二进制数据进行base64转码
        NSString *result = [encryptData base64EncodedStringWithOptions:0];
        NSLog(@"加密结果result === %@", result);
        NSString *ivEncodeStr = [self base64EncodeString:ivStr];
        NSString *mac256Str = [NSString stringWithFormat:@"%@%@", ivEncodeStr, result];
        // 生成mac
        NSString *mac = [self hmac256:mac256Str withKey:keyDecodeStr];
        
        NSDictionary *dict = @{
            @"iv" : kCheckString(ivEncodeStr),
            @"value" : kCheckString(result),
            @"mac" : kCheckString(mac),
        };
        NSLog(@"加密后组合dictionary === %@", dict);
        
        NSString *dictStr = [BWMethod objectToJsonString:dict];
        
        return [self base64EncodeString:dictStr];
    } else {
        free(buffer);
        return nil;
    }
}


+ (NSString *)hmac256:(NSString *)plaintext withKey:(NSString *)key {
    const char *cKey  = [key cStringUsingEncoding:NSASCIIStringEncoding];
    const char *cData = [plaintext cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
    NSData *HMACData = [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)];
    const unsigned char *buffer = (const unsigned char *)[HMACData bytes];
    NSMutableString *HMAC = [NSMutableString stringWithCapacity:HMACData.length * 2];
    for (int i = 0; i < HMACData.length; ++i){
        [HMAC appendFormat:@"%02x", buffer[i]];
    }
    
    return HMAC;
}

/// AES解密
+ (NSString *)aesDecrypt:(NSString *)secretStr {
    if (!secretStr) {
        return nil;
    }
    
    // 获取json payload
    NSDictionary *payload = [self getJsonPaylod:secretStr];
    
    // 截取SecurityKey
    NSString *subAesStr = [SecretKey substringWithRange:NSMakeRange(8, SecretKey.length - 16)];
    //先对加密的字符串进行base64解码
    NSString *keyDecodeStr = [self base64DecodeString:subAesStr];
    
    // 设置密钥
    char keyPtr[kCCKeySizeAES256 + 1];
    bzero(keyPtr, sizeof(keyPtr));
    [keyDecodeStr getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    // 设置iv
    NSString *ivStr = [payload[@"iv"] description];
    NSString *ivDecodeStr = [self base64DecodeString:ivStr];
    char ivPtr[kCCKeySizeAES128 + 1];
    bzero(ivPtr, sizeof(ivPtr));
    [ivDecodeStr getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
    
    // 需要解密的数据
    NSString *valueStr = [payload[@"value"] description];
    NSData *valueData = [[NSData alloc] initWithBase64EncodedString:valueStr options:0];
    NSArray *array = [NSArray array];
    NSLog(@"valueData === %@", valueData);
    
    // 设置输出缓冲区
    NSUInteger dataLength = valueData.length;
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesDecrypted = 0;
    
    /*
     CCCrypt(
        kCCEncrypt,         // 加密还是解密, kCCEncrypt 加密/kCCDecrypt 解密
        encryptionType,     // 加密的方式 DES, 3DES, AES, 默认的 AES/DES
        kCCOptionPKCS7Padding|kCCOptionECBMode, // 加密方式的选项  kCCOptionPKCS7Padding: CBC加密！    kCCOptionECBMode: ECB加密！
        [key UTF8String],   // 加密密钥, 把key转换为C串
        keyLength,          // 秘钥的长度，固定的 kCCKeySizeDES,kCCKeySize3DES
        nil,                // iv 初始化向量，ECB 不需要指定
        [baseData bytes],   // 加密的数据
        [baseData length],  // 加密的数据长度
        buffer,             // 缓冲区（地址），存放密文的, 注意接收加密的buffer的大小
        dataLength,         // 缓冲区的大小
        &dataOutOffset      // 加密结果大小
     );
     */
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmAES,
                                          kCCOptionPKCS7Padding,
                                          keyPtr,
                                          kCCKeySizeAES256,
                                          ivPtr,
                                          valueData.bytes,
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesDecrypted);
    
    if (cryptStatus == kCCSuccess) {
        NSData *data = [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
        NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
        return result;
    } else {
        free(buffer);
        NSLog(@"[错误] 解密失败|状态编码: %d", cryptStatus);
        return nil;
    }
}

/// 获取json payload
+ (NSDictionary *)getJsonPaylod:(NSString *)cipherText {
    NSData *decodeData = [[NSData alloc] initWithBase64EncodedString:cipherText options:NSDataBase64DecodingIgnoreUnknownCharacters];
    NSString *decodeStr = [[NSString alloc] initWithData:decodeData encoding:NSUTF8StringEncoding];
    NSDictionary *dict = [BWMethod dictionaryWithJsonString:decodeStr];
    NSLog(@"getJsonPaylod === %@", dict);
    return dict;
}

/// 生成随机字符串
+ (NSString *)getRandomStringWithNum:(NSInteger)num {
    NSString *string = [[NSString alloc] init];
    for (int i = 0; i < num; i++) {
        int number = arc4random() % 36;
        if (number < 10) {
            int figure = arc4random() % 10;
            NSString *tempString = [NSString stringWithFormat:@"%d", figure];
            string = [string stringByAppendingString:tempString];
        } else {
            int figure = (arc4random() % 26) + 97;
            char character = figure;
            NSString *tempString = [NSString stringWithFormat:@"%c", character];
            string = [string stringByAppendingString:tempString];
        }
    }
    return string;
}

@end
